﻿using APILibrary.TypeDic;
using RazorEngine;
using RazorEngine.Templating;
using RazorTs.ModelInfo;
using RazorTs.TemplateAxios;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
using TsInterfaceRazor.analysis;
using TsInterfaceRazor.ModelInfo;

namespace RazorTs.analysis
{
    /// <summary>
    /// 分析入口
    /// </summary>
    public class Entry
    {
        public static string AppendString = @"
/**分页返回数据**/
export interface PageList<T>
        {
            /**API结果代码**/
            ResultCode: number
/**API错误/正常消息内容**/ 
Message: string
/**数据总行数**/ 
Pagerecords: number
/**当前页码**/ 
PageIndex: number
/**每页要显示的行数**/
PageTotal: number
/**数据实体**/
Data: Array<T> | null
}

        export interface ModelEntity<T>
        {
            /**API结果代码**/
            ResultCode: number
/**API错误/正常消息内容**/ 
Message: string
/**数据实体**/ 
Data: T
        }
export interface ListEntity<T> {
  /**API结果代码**/
  ResultCode: number
  /**API错误/正常消息内容**/
  Message: string
  /**数据实体**/
  Data: Array<T> | null
}";
        /// <summary>
        /// 入口文件
        /// </summary>
        /// <param name="type"></param>
        /// <param name="templateMethod"></param>
        /// <param name="templateInterface"></param>
        /// <param name="customGenericsType"></param>
        /// <param name="path"></param>
        public static  void Start(Type type,string templateMethod, string templateInterface, string templateEnum, Dictionary<string,string> customGenericsType,string path,string appendString)
        {
            var destinationPath = "";
            Assembly ass = Assembly.GetAssembly(type);
            //获取所有的类型
            Type[] types = ass.GetTypes();
            List<ApiDescribe> apisDescribe = new List<ApiDescribe>();
            foreach (var t in types)
            {
                var modelString = new StringBuilder();
                apisDescribe = new List<ApiDescribe>();
                ToTs.ModelDescribes = new List<ModelDescribe>();
                ToTs.ClassNames = new List<string>();
                AnalysisType.tsEnums = new List<TsEnum>();
                //判断是否集成该接口
                if (t.GetInterface("IAPIDocument") != null)
                {
                    destinationPath = path + "\\"+t.AssemblyQualifiedName.Split(',')[1];
                    //过滤方法
                    foreach (var method in t.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Static))
                    {
                        AnalysisType.IsT = false;
                        ApiDescribe apiDescribe = new ApiDescribe();

                        var isPost = method.GetCustomAttribute(typeof(HttpPostAttribute));
                        var isGet = method.GetCustomAttribute(typeof(HttpGetAttribute));

                        apiDescribe.MethodName = method.Name;
                        apiDescribe.Describe = ToTs.GetDescribe(method);

                        //判断是否是带谓词的方法
                        if (isPost != null)
                        {
                            var sRetrun = AnalysisType.GetMethodReturn(method.ReturnType);
                            Console.WriteLine(sRetrun);
                            apiDescribe.ApiUrl = $"/api/{t.Name.Replace("Controller", "")}/{method.Name}";
                            apiDescribe.ReturnValue = sRetrun;
                            apiDescribe.RequestMethod = "post";
                            var parameters = method.GetParameters();
                         
                            List<ModelPropertyDescribe> modelPropertyDescribes = new List<ModelPropertyDescribe>();
                            foreach (var parameter in parameters)
                            {
                                apiDescribe.IsNullParam = false;
                                ModelPropertyDescribe modelPropertyDescribe = new ModelPropertyDescribe();
                                var isData = parameter.GetCustomAttribute(typeof(FromBodyAttribute));
                                if (isData != null)
                                {
                                    modelPropertyDescribe.PropertyName = parameter.Name;
                                    modelPropertyDescribe.PropertyType = parameter.ParameterType.Name;
                                    modelPropertyDescribe.PropertyDescribe = ToTs.GetDescribe(parameter.ParameterType);
                                    apiDescribe.ModelPropertyParameterDescribes.Add(modelPropertyDescribe);
                                    var isResult = ToTs.GetModelDescribes(parameter.ParameterType);
                                    apiDescribe.IsParams = false;
                                    apiDescribe.IsData = true;
                                }
                                else
                                {
                                    if (parameter.ParameterType.IsIEnumerableType())
                                    {//是否是IsIEnumerableType

                                        var rootType = parameter.ParameterType.GetGenericArguments()[0];

                                        if (rootType.IsClass && rootType.Name != "String")
                                        {//如果是类的话
                                            modelPropertyDescribe.PropertyType += "Array<";
                                            modelPropertyDescribe.PropertyType += rootType.Name;
                                            modelPropertyDescribe.PropertyType += ">";
                                        }
                                        else
                                        {
                                            if (rootType.IsNullableType())
                                            {
                                                var rootType2 = rootType.GetGenericArguments()[0];
                                                modelPropertyDescribe.PropertyType += "Array<";
                                                modelPropertyDescribe.PropertyType += APILibrary.TypeDic.TypeDic.TsTypeDic[rootType2.ToString().Split('.')[rootType2.ToString().Split('.').Length - 1]];
                                                //modelPropertyDescribe.PropertyType += "| null";
                                                modelPropertyDescribe.IsNull = true;
                                                modelPropertyDescribe.PropertyType += ">";
                                            }
                                            else
                                            {
                                                modelPropertyDescribe.PropertyType += "Array<";
                                                modelPropertyDescribe.PropertyType += APILibrary.TypeDic.TypeDic.TsTypeDic[rootType.ToString().Split('.')[rootType.ToString().Split('.').Length - 1]];
                                                modelPropertyDescribe.PropertyType += ">";
                                                //if (k.IsNullableType())
                                                //{
                                                //    modelPropertyDescribe.PropertyType += "|| null";
                                                //}
                                            }
                                        }


                                    }
                                    else
                                    {
                                        if (parameter.ParameterType.IsNullableType())
                                        {
                                            var rootType = parameter.ParameterType.GetGenericArguments()[0];
                                            modelPropertyDescribe.PropertyType = APILibrary.TypeDic.TypeDic.TsTypeDic[rootType.ToString().Split('.')[rootType.ToString().Split('.').Length - 1]];
                                            //modelPropertyDescribe.PropertyType += "| null";
                                            modelPropertyDescribe.IsNull = true;
                                        }
                                        else
                                        {
                                            var resultType = AnalysisType.Start(parameter.ParameterType);
                                            if (resultType.TypeEnum == TypeEnum.Enum)
                                            {
                                                modelPropertyDescribe.PropertyType = parameter.ParameterType.Name;
                                                AnalysisType.GenerateEnum(parameter.ParameterType);
                                            }
                                            else
                                            {
                                                modelPropertyDescribe.PropertyType = APILibrary.TypeDic.TypeDic.TsTypeDic[parameter.ParameterType.Name.ToString().Split('.')[parameter.ParameterType.Name.ToString().Split('.').Length - 1]];
                                            }

                                        }
                                    }

                                    modelPropertyDescribe.PropertyName = parameter.Name;
                                    modelPropertyDescribe.PropertyDescribe = ToTs.GetDescribe(parameter);
                                }
                                modelPropertyDescribes.Add(modelPropertyDescribe);
                            }
                            apiDescribe.ModelPropertyParameterDescribes = modelPropertyDescribes;
                        }

                        if (isGet != null)
                        {
                            var sRetrun = AnalysisType.GetMethodReturn(method.ReturnType);
                            Console.WriteLine(sRetrun);
                            apiDescribe.ApiUrl = $"/api/{t.Name.Replace("Controller", "")}/{method.Name}";
                            apiDescribe.ReturnValue = sRetrun;
                            apiDescribe.RequestMethod = "get";
                            var parameters = method.GetParameters();
                            List<ModelPropertyDescribe> modelPropertyDescribes = new List<ModelPropertyDescribe>();

                            foreach (var parameter in parameters)
                            {
                                apiDescribe.IsNullParam = false;
                                ModelPropertyDescribe modelPropertyDescribe = new ModelPropertyDescribe();
                                var abs = ToTs.GetDescribe(parameter);
                                var isData = parameter.GetCustomAttribute(typeof(FromBodyAttribute));
                                if (isData != null)
                                {
                                    modelPropertyDescribe.PropertyName = parameter.Name;
                                    modelPropertyDescribe.PropertyType = parameter.ParameterType.Name;
                                    modelPropertyDescribe.PropertyDescribe = ToTs.GetDescribe(parameter.ParameterType);
                                    var isResult = ToTs.GetModelDescribes(parameter.ParameterType);
                                    apiDescribe.IsParams = false;
                                    apiDescribe.IsData = true;
                                }
                                else
                                {

                                    if (parameter.ParameterType.IsIEnumerableType())
                                    {//是否是IsIEnumerableType

                                        var rootType = parameter.ParameterType.GetGenericArguments()[0];

                                        if (rootType.IsClass && rootType.Name != "String")
                                        {//如果是类的话
                                            modelPropertyDescribe.PropertyType += "Array<";
                                            modelPropertyDescribe.PropertyType += rootType.Name;
                                            modelPropertyDescribe.PropertyType += ">";
                                        }
                                        else
                                        {
                                            if (rootType.IsNullableType())
                                            {
                                                var rootType2 = rootType.GetGenericArguments()[0];
                                                modelPropertyDescribe.PropertyType += "Array<";
                                                modelPropertyDescribe.PropertyType += APILibrary.TypeDic.TypeDic.TsTypeDic[rootType2.ToString().Split('.')[rootType2.ToString().Split('.').Length - 1]];
                                                //modelPropertyDescribe.PropertyType += "| null";
                                                modelPropertyDescribe.IsNull = true;
                                                modelPropertyDescribe.PropertyType += ">";
                                            }
                                            else
                                            {
                                                modelPropertyDescribe.PropertyType += "Array<";
                                                modelPropertyDescribe.PropertyType += APILibrary.TypeDic.TypeDic.TsTypeDic[rootType.ToString().Split('.')[rootType.ToString().Split('.').Length - 1]];
                                                modelPropertyDescribe.PropertyType += ">";
                                                //if (k.IsNullableType())
                                                //{
                                                //    modelPropertyDescribe.PropertyType += "|| null";
                                                //}
                                            }
                                        }


                                    }
                                    else
                                    {
                                        if (parameter.ParameterType.IsNullableType())
                                        {
                                            var rootType = parameter.ParameterType.GetGenericArguments()[0];
                                            modelPropertyDescribe.PropertyType = APILibrary.TypeDic.TypeDic.TsTypeDic[rootType.ToString().Split('.')[rootType.ToString().Split('.').Length - 1]];
                                            //modelPropertyDescribe.PropertyType += "| null";
                                            modelPropertyDescribe.IsNull = true;
                                        }
                                        else
                                        {
                                            var resultType = AnalysisType.Start(parameter.ParameterType);
                                            if (resultType.TypeEnum == TypeEnum.Enum)
                                            {
                                                modelPropertyDescribe.PropertyType = parameter.ParameterType.Name;
                                                AnalysisType.GenerateEnum(parameter.ParameterType);
                                            }
                                            else
                                            {
                                                modelPropertyDescribe.PropertyType = APILibrary.TypeDic.TypeDic.TsTypeDic[parameter.ParameterType.Name.ToString().Split('.')[parameter.ParameterType.Name.ToString().Split('.').Length - 1]];
                                            }
                                           
                                        }
                                    }

                                    modelPropertyDescribe.PropertyName = parameter.Name;
                                    modelPropertyDescribe.PropertyDescribe = ToTs.GetDescribe(parameter);
                                }
                                modelPropertyDescribes.Add(modelPropertyDescribe);

                            }
                            apiDescribe.ModelPropertyParameterDescribes = modelPropertyDescribes;
                        }

                        apisDescribe.Add(apiDescribe);

                        if (AnalysisType.IsT)
                        {
                            var result = AnalysisType.Start(method.ReturnType.GetGenericArguments()[0]);
                            if (result.TypeEnum != TypeEnum.BaseType)
                            {
                                var result111 = ToTs.GetModelDescribes(method.ReturnType.GetGenericArguments()[0]);
                            }
                        }
                        else
                        {

                            var result111 = ToTs.GetModelDescribes(method.ReturnType);
                        }
                    }


                    ToTs.ModelDescribes = ToTs.ModelDescribes.GroupBy(e => e.ClassName).Select(d => d.FirstOrDefault()).ToList();

                    //接口生成
                    foreach (var interfaceDescribe in ToTs.ModelDescribes)
                    {
                        var result1 = Engine.Razor.RunCompile(templateInterface, "templateKey", null, interfaceDescribe);

                        result1 = result1.Replace("&lt;", "<");
                        result1 = result1.Replace("&gt;", ">");
                        Console.WriteLine(result1);
                        modelString.Append(result1);
                    }
                   
                    //api生成
                    foreach (var item in apisDescribe)
                    {
                        var describes = new StringBuilder();
                        describes.Append("/**");
                        describes.Append($"* {item.Describe}");

                        var sss = "";
                        int i = 0;
                        var s = new StringBuilder();
                        var ss = new StringBuilder();
                        ss.Append("{");
                        foreach (var item3 in item.ModelPropertyParameterDescribes)
                        {
                            describes.Append($"* @param {item3.PropertyName} {item3.PropertyDescribe}");
                            s.Append(item3.PropertyName + (item3.IsNull ? "?" : "") + ":" + item3.PropertyType + ",");
                            ss.Append(item3.PropertyName + ":" + item3.PropertyName + ",");
                            if (i == 0)
                            {
                                sss = item3.PropertyName;
                            }
                        }
                        if (item.ModelPropertyParameterDescribes.Count() > 0)
                        {
                            s.Remove(s.Length - 1, 1);
                            ss.Remove(ss.Length - 1, 1);
                            ss.Append("}");
                            item.ParameterString = s.ToString();
                            item.Params = ss.ToString();
                            if (item.IsData)
                            {
                                item.Data = sss;
                            }
                        }

                        describes.Append($" * @returns");
                        describes.Append($" */");
                        item.Describes = describes.ToString();
                    }

                    //枚举值生成
                    if (AnalysisType.tsEnums.Count() > 0)
                    {
                        var resultEnum = Engine.Razor.RunCompile(templateEnum, "templateKeyEnum", null, AnalysisType.tsEnums);

                        resultEnum = resultEnum.Replace("&lt;", "<");
                        resultEnum = resultEnum.Replace("&gt;", ">");
                        Console.WriteLine(resultEnum);
                        modelString.Append(resultEnum);
                    }

                    ToTs.ModelDescribes = new List<ModelDescribe>();
                    ToTs.ClassNames = new List<string>();
                    AnalysisType.tsEnums = new List<TsEnum>();


                    Console.WriteLine(AnalysisType.tsEnums.Count());

                    var resultString = Engine.Razor.RunCompile(templateMethod, "templateKey222", null, apisDescribe);
                    resultString = resultString.Replace("&lt;", "<");
                    resultString = resultString.Replace("&gt;", ">");
                    var nameFile = t.Name.Replace("Controller", "");
                     GenerateFile(destinationPath, $"\\{nameFile}.ts", resultString + modelString+appendString);
                    Console.WriteLine(resultString);
                }




            }
        }


        private static void  GenerateFile(string directoryPath,string path, string content)
        {

            if (File.Exists(directoryPath+path))
            {
                File.Delete(directoryPath+path);
            }
            if (!Directory.Exists(directoryPath))
            {
                Directory.CreateDirectory(directoryPath);
            }
            

            //创建文本文件Demo.txt，并写入初始字符串"123456789"
            using (var fileStream = new FileStream(directoryPath+path, FileMode.CreateNew))
            {
                var result = content.Replace(";", "\r\n");
                byte[] data = System.Text.Encoding.UTF8.GetBytes(result);//
                fileStream.Write(data, 0, data.Length);

            }
        }
    }
}
